import os
import re
import struct

from spark import SparkApi
from speechmodules.speech2text import BaiduASR, AzureASR
from speechmodules.text2speech import BaiduTTS, AzureTTS
from speechmodules.wakeword import PicoWakeWord

# --------------------picovoice--------------------
# 你的picovoice key
PICOVOICE_API_KEY = "l/83vyWAtsnxY5qXnFIZ7etoPXsVPeHOVih3emZs6vk6McOHpJ0Ang=="
# 你的唤醒词检测离线文件地址
KEYWORD_PATH = '/speechmodules/heysiri_windows.ppn'
# --------------------picovoice--------------------

# --------------------百度--------------------
# 你的百度APP_ID
BAIDU_APP_ID = '53553455'
# 你的百度API_KEY
BAIDU_API_KEY = 'zYhlJ28DOiFj6S6rI0vowKmC'
# 你的百度SECRET_KEY
BAIDU_SECRET_KEY = 'iLAVDDBcKmpCUX2RkshOW9kTAWoQV74F'
# --------------------百度--------------------

# --------------------azure--------------------
# 你的azure key
AZURE_API_KEY = "cebe49c14ae9471c8b80c8604b851afa"
# 你的azure region
AZURE_REGION = "southeastasia"
# --------------------azure--------------------

# --------------------科大讯飞--------------------
# 填写控制台中获取的 APPID 信息
SPARK_APPID = "7285e9de"
# 填写控制台中获取的 APISecret 信息
SPARK_API_SECRET = "OWZiMDZjMjI1NDllMzg4YWNiOGU3ZTBl"
# 填写控制台中获取的 APIKey 信息
SPARK_API_KEY = "4c82e156990bd5d182336fb6b5df3765"
# 以下两个不用改
SPARK_URL = "wss://spark-api.xf-yun.com/v3.5/chat"
SPARK_DOMAIN = "generalv3.5"
# --------------------科大讯飞--------------------


def find_music_file(music_folder, song_name):
    for file_name in os.listdir(music_folder):
        if song_name.lower() in file_name.lower():
            return os.path.join(music_folder, file_name)
    return None


def extract_song_name(command):
    match = re.search(r"播放[，,\s]*(.+?)[，。,.]", command)
    if match:
        return match.group(1).strip()
    return None

def run(picowakeword, asr, tts):
    while True:  # 需要始终保持对唤醒词的监听
        audio_obj = picowakeword.stream.read(picowakeword.porcupine.frame_length, exception_on_overflow=False)
        audio_obj_unpacked = struct.unpack_from("h" * picowakeword.porcupine.frame_length, audio_obj)
        keyword_idx = picowakeword.porcupine.process(audio_obj_unpacked)
        if keyword_idx >= 0:
            print("嗯,我在,请讲！")
            tts.play_voice_open()
            # 语音识别3次后即代表没有说话，进入等待唤醒状态
            count = 0

            while True:  # 进入一次对话session
                req = asr.speech_to_text()
                if (req is None) or len(req) < 1:
                    if count >= 3:
                        break  # 退出当前对话 session
                    count += 1
                    continue
                count = 0

                # 查找歌曲名称
                song_name = extract_song_name(req)
                if song_name:
                    music_file_path = find_music_file(os.path.dirname(os.path.abspath(__file__)) + "/music", song_name)
                    if music_file_path:
                        # 播放音乐
                        tts.play_voice_ok()
                        tts.play_audio_with_pygame(music_file_path)
                    else:
                        # 没有该音乐
                        tts.play_voice_nomusic()
                    break  # 音乐播放完毕，退出当前对话 session

                # 科大讯飞回答
                SparkApi.doAnswer(SPARK_APPID, SPARK_API_KEY, SPARK_API_SECRET, SPARK_URL, SPARK_DOMAIN, req)
                res = SparkApi.answer
                print(res)
                tts.text_to_speech_and_play(res)


def Orator():
    directory = os.path.dirname(os.path.abspath(__file__))
    picowakeword = PicoWakeWord(PICOVOICE_API_KEY, directory + KEYWORD_PATH)
    # 百度语音识别和语音合成
    asr = BaiduASR(BAIDU_APP_ID, BAIDU_API_KEY, BAIDU_SECRET_KEY)
    tts = BaiduTTS(BAIDU_APP_ID, BAIDU_API_KEY, BAIDU_SECRET_KEY)
    # Azure语音识别和语音合成
    # asr = AzureASR(AZURE_API_KEY, AZURE_REGION)
    # tts = AzureTTS(AZURE_API_KEY, AZURE_REGION)

    try:
        run(picowakeword, asr, tts)
    except KeyboardInterrupt:
        exit(0)
    finally:
        print('本轮对话结束')
        tts.play_voice_exit()
        Orator()


if __name__ == '__main__':
    Orator()
